package cn.tom.service;

import cn.hutool.json.JSONUtil;
import cn.tom.dao.BookMapper;
import cn.tom.dao.CartMapper;
import cn.tom.dao.OrderMapper;
import cn.tom.entity.*;
import cn.tom.exceptiom.TomException;

import cn.tom.tool.InitData;
import cn.tom.tool.RedisCache;
import org.apache.commons.lang3.math.NumberUtils;
import org.checkerframework.checker.units.qual.A;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;

@Service
public class OrderServiceImpl implements OrderService {
    private Logger log = LoggerFactory.getLogger(getClass());
    @Autowired(required = false)
    OrderMapper orderMapper;

    @Autowired(required = false)
    CartMapper cartMapper;

    @Autowired(required = false)
    BookMapper bookMapper;

    @Autowired
    RedisCache redisCache;

    /*@Override
    @Transactional(rollbackFor = {Exception.class})
    public int doPay(int ordid, Integer payStatus) {
        List<Integer> list = this.orderMapper.findItemsBookIdByOrdid(ordid);
        Map<String,Object> map = new HashMap<>();
        map.put("ordid",ordid);
        map.put("list",list);
        System.out.println(map);
        List<OrdItem> items = this.orderMapper.findItemsByOrdid2(map);
        for (OrdItem item : items) {
            System.out.println("000000000000" + item);
        }
        for (OrdItem itm : items) {
            list.add(itm.getBook().getId());
            if (itm.getNum() > itm.getBook().getStock()) {
                throw new RuntimeException("付款失败, 库存不足无法出货...");
            }
            if (itm.getNum() <= itm.getBook().getStock() && this.bookMapper.subtractStock(itm.getBook().getId(), -1 * itm.getNum()) == 0) {
                throw new RuntimeException("付款失败， 无法更新库存...");
            }

        }
        if (this.orderMapper.updatePay(ordid, payStatus) != 0) {
            return 1;
        }
        throw new RuntimeException("付款失败...");
    }*/

    /* @Resource
     private DefaultRedisScript<Long> redisScript;*/
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    InitData initData;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int doPay(int ordid, Integer payStatus) {
        //更新库存
        Map<String, Object> stock = redisCache.getCacheMap("stock");
        if (stock.size()==0) {
            initData.stock();
        }
        List<OrdItem> items = orderMapper.findItemsByOrdid(ordid);
        // List<String> res = new ArrayList<>();
        for (OrdItem itm : items) {
            System.out.println("=======aaaa======");
            System.out.println("bookid==="+  itm.getBook().getId()+ "||||||num" + itm.getNum());
            // 使用集合来存储Redis keys
            List<String> keys = Collections.singletonList("stock");
            // 将扣减的数量和书的ID存储到一个列表中
            List<String> args = Arrays.asList(String.valueOf(itm.getNum()), String.valueOf(itm.getBook().getId()));
            // 执行 lua 脚本
            DefaultRedisScript<String> redisScript = new DefaultRedisScript<>();
            // 指定 lua 脚本
            redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("lua/order.lua")));
            // 指定返回类型
            redisScript.setResultType(String.class);
            // 执行脚本
            String result = stringRedisTemplate.execute(redisScript, keys, args.toArray());
            if (result != null && NumberUtils.isDigits(result)) {
                //返回书本的新库存
                System.out.println("========脚本返回值====" + result);
                //res.add(result);
                int i = this.bookMapper.updateStock(itm.getBook().getId(), Integer.parseInt(result));
                if (i == 0) {
                    redisCache.deleteObject("stock");
                    throw new TomException("数据库更新库存失败");
                }
            } else if (result.equals("INSUFFICIENT_STOCK")) {
                System.out.println("库存不足");
                redisCache.deleteObject("stock");
                throw new TomException("库存不足");
            } else {
                System.out.println("其他原因");
                redisCache.deleteObject("stock");
                throw new TomException(result);
            }
            System.out.println("=======bbb======");
        }
       /* for (String s : res) {
            int i = this.bookMapper.updateStock(itm.getBook().getId(), Integer.parseInt(result));
            if (i == 0) {
                throw new TomException("数据库更新库存失败");
            }
        }*/
        if (this.orderMapper.updatePay(ordid, payStatus) != 0) {
            return 1;
        }
        throw new TomException("付款失败...");
    }

    /* @Override*/
    @Transactional(rollbackFor = Exception.class)
    public int doPay2(int ordid, Integer payStatus) {
        Map<String, Book> books = redisCache.getCacheMap("books"); //获取redis缓存的商品信息
        //更新库存
        synchronized (this) {
            List<OrdItem> items = orderMapper.findItemsByOrdid(ordid);
            for (OrdItem itm : items) {
                String bookid = String.valueOf(itm.getBook().getId());
                Book book = books.get(bookid);

                System.out.println("2121212121=" + book);
                if (itm.getNum() > book.getStock()) {
                    throw new TomException("付款失败, 库存不足无法出货...");
                }
                if (itm.getNum() <= book.getStock() && this.bookMapper.subtractStock(itm.getBook().getId(), -1 * itm.getNum()) == 0) {
                    throw new TomException("付款失败， 无法更新库存...");
                }
                book.setStock(book.getStock() - itm.getNum());
                //更新redis缓存
                redisCache.setOneMap("books", String.valueOf(itm.getBook().getId()), book);
            }
        }
        if (this.orderMapper.updatePay(ordid, payStatus) != 0) {
            return 1;
        }
        throw new TomException("付款失败...");
    }


    @Override
    public Order findByOrdId(int ordid) {
        return this.orderMapper.findOrdById(ordid);
    }

    @Override
    public int getCountOrdersByUid(Map<String, Object> map) {
        return this.orderMapper.getCountOrdersByUid(map);
    }

    @Override
    public List<Order> findPageOrdersByUid(Map<String, Object> map) {
        return this.orderMapper.findPageOrdersByUid(map);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void uniaddCart2Ord(UniCart2Ord uniCart2Ord) {
        Order ord = new Order();

        ord.setUid(uniCart2Ord.getUid());
        ord.setPayStatus(0); //发货状态

        ord.setShip2name(uniCart2Ord.getShip2name());
        ord.setShip2phone(uniCart2Ord.getShip2phone());
        ord.setShip2addr(uniCart2Ord.getShip2addr());
        List<OrdItem> items = new ArrayList<>();
        ord.setItems(items);
        List<Cart> list = JSONUtil.toList(uniCart2Ord.getCarts(), Cart.class);
        for (Cart c : list) {
            OrdItem i = new OrdItem();
            i.setOrdid(0);
            i.setBook(c.getBook());
            i.setItemid(c.getId()); //先把购物车id加入明细表id 后面添加明细表时候不使用setItemId
            i.setNum(c.getNum());
            i.setPrice(c.getPrice());
            items.add(i);
        }
        //
        double amount = 0.00d;
        for (OrdItem item : items) {
            amount += ((double) item.getNum()) * item.getPrice();
        }
        uniCart2Ord.setAmount(amount); //插入订单总额
        ord.setAmount(amount);
        this.orderMapper.addOrd(ord);
        int ordid = ord.getOrdid(); //拿到订单添加返回的订单id

        uniCart2Ord.setOrdid(ordid);
        this.log.info("===========cart2Ord.setOrdid(ordid) ordid=" + ordid);
        if (ordid < 1) {
            throw new RuntimeException("插入订单失败, 没有获取主键, 终止事务");
        }
        this.log.info("=============执行数据items =" + items.toString());
        this.log.info("===========item.size" + items.size());
        for (OrdItem item2 : items) {
            item2.setOrdid(ordid);
            //删除购物车数据
            this.cartMapper.remove(item2.getItemid());
            this.log.info("remove =" + item2.getItemid());

            //添加订单明细
            this.orderMapper.addItem(item2);
            this.log.info("addItm =" + item2.toString());
            //书本销量增加

            this.bookMapper.addSalenum(item2.getBook().getId(), item2.getNum());
            this.log.info("add salenum =" + item2.getBook().getId());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addCart2Ord(Cart2Ord cart2Ord) {
        Order ord = new Order();

        ord.setUid(cart2Ord.getUid());
        ord.setPayStatus(0); //发货状态

        ord.setShip2name(cart2Ord.getShip2name());
        ord.setShip2phone(cart2Ord.getShip2phone());
        ord.setShip2addr(cart2Ord.getShip2addr());
        List<OrdItem> items = new ArrayList<>();
        ord.setItems(items);
        for (Cart c : cart2Ord.getCarts()) {
            OrdItem i = new OrdItem();
            i.setOrdid(0);
            i.setBook(c.getBook());
            i.setItemid(c.getId()); //先把购物车id加入明细表id 后面添加明细表时候不使用setItemId
            i.setNum(c.getNum());
            i.setPrice(c.getPrice());
            items.add(i);
        }
        //
        double amount = 0.00d;
        for (OrdItem item : items) {
            amount += ((double) item.getNum()) * item.getPrice();
        }
        cart2Ord.setAmount(amount); //插入订单总额
        ord.setAmount(amount);
        this.orderMapper.addOrd(ord);
        int ordid = ord.getOrdid(); //拿到订单添加返回的订单id

        cart2Ord.setOrdid(ordid);
        this.log.info("===========cart2Ord.setOrdid(ordid) ordid=" + ordid);
        if (ordid < 1) {
            throw new RuntimeException("插入订单失败, 没有获取主键, 终止事务");
        }
        this.log.info("=============执行数据items =" + items.toString());
        this.log.info("===========item.size" + items.size());
        for (OrdItem item2 : items) {
            item2.setOrdid(ordid);
            //删除购物车数据
            this.cartMapper.remove(item2.getItemid());
            this.log.info("remove =" + item2.getItemid());

            //添加订单明细
            this.orderMapper.addItem(item2);
            this.log.info("addItm =" + item2.toString());
            //书本销量增加

            this.bookMapper.addSalenum(item2.getBook().getId(), item2.getNum());
            this.log.info("add salenum =" + item2.getBook().getId());
        }
    }

    @Override
    public int getCountOrders2u(Map<String, Object> map) {
        return this.orderMapper.getCountOrders2u(map);
    }

    @Override
    public List<Order2u> findPageOrders2u(Map<String, Object> map) {
        return this.orderMapper.findPageOrders2u(map);
    }

    @Override
    public int updateShip(int ordid, int shipStatus, String shipno, String shipper, Date tship) {
        return this.orderMapper.updateShip(ordid, shipStatus, shipno, shipper, tship);
    }

    @Override
    public Order2u findOrder2uByOrdid(int ordid) {
        return this.orderMapper.findOrder2uByOrdid(ordid);
    }

    @Override
    public List<Integer> findBookidByOrdid(int ordid) {
        return this.orderMapper.findBookidByOrdid(ordid);
    }


    /* @Override
    public List<Order> findOrdByUid(int i) {
        return this.orderMapper.findOrdByUid(i);
    }*/
}
